<?php
// +----------------------------------------------------------------------
// | 链乡 [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017 http://www.twothink.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: codeshuhao
// +----------------------------------------------------------------------

namespace app\admin\servlet;


use think\facade\Log;

class BuildServlet extends BaseServlet
{

    /**
     * 递归处理多维数组为空转为false
     * @param array $data
     * @return array
     */
    private function filter_recursive($data = array())
    {
        return array_map(function($item)
        {
            if( is_array($item) )
            {
                $item = $this->filter_recursive($item);
            }

            return $item == '' ? false : $item;
        },
            $data);
    }


    /**
     * 验证数据是否正确
     * @param array $data
     * @return array|bool
     */
    public function validity($data = array())
    {
        // 递归处理多维数组为空转为false
        $data = $this->filter_recursive($data);

        // 必填字段
        $require = [
            'module' => '模块名称',
            'title' => '应用名称',
            'target' => '对象名称',
        ];

        // 必填字段提醒
        foreach ($require as $key => $label)
        {
            if( empty($data[$key]) )
            {
                $this->error = sprintf('【%s】不能为空',$label);

                return false;
            }
        }

        return $data;
    }


    /**
     * 构建各层目录及文件和数据填充模板
     * @param array $data
     * @return array
     */
    public function inquire($data = array())
    {
        // 对象名称
        $data['target'] = ucfirst($data['target']);
        // 对象实例名称
        $data['instance'] = lcfirst($data['target']);

        // 模板视图层目录
        $buildView = sprintf('%s%s/%s/%s',APPLICATION_PATH,'admin','view','build');

        // 构建各层目录及文件
        foreach ($data['layer'] as $key => $item)
        {
            if( empty($item) == false )
            {
                $file = sprintf('%s%s/%s/%s%s',APPLICATION_PATH,$data['module'],lcfirst($key),$item,'.php');
                //模板路径
                $templates = sprintf('%s/%s/%s%s',$buildView,'layer',$key,'.html');
                //需要创建的目录
                $data['dir'][$key] = sprintf('%s%s/%s',APPLICATION_PATH,$data['module'],$key);
                $data['file'][$key] = $file;
                $data['fetch'][$file] = $templates;
            }
        }

        // 构建数据层目录及文件
        foreach ($data['data'] as $key => $item)
        {
            if( empty($item) == false )
            {
                $file = sprintf('%s/%s/%s%s',COMMON_PATH,lcfirst($key),$item,'.php');
                //模板路径
                $templates = sprintf('%s/%s/%s%s',$buildView,'data',$key,'.html');
                $data['dir'][$key] = sprintf('%s/%s',COMMON_PATH,lcfirst($key));
                $data['file'][$key] = $file;
                $data['fetch'][$file] = $templates;
            }
        }

        // 对象视图层目录
        $view = sprintf('%s%s/%s/%s',APPLICATION_PATH,lcfirst($data['module']),'view',strtolower(preg_replace('/(?<=[a-z])([A-Z])/', '_$1', $data["target"])));

        $data['view'] = $view;

        // 构建视图层文件
        if( empty($data['method']) === false)
        {
            foreach ($data['method'] as $item)
            {
                if( in_array($item,array('delete')) === false )
                {
                    $file = sprintf('%s/%s%s',$view,$item,'.html');
                    $data['file'][$item] = $file;
                    $templates = sprintf('%s/%s/%s/%s%s',$buildView,'method',$data['theme'],$item,'.html');
                    $data['templates'][$file] = $templates;
                }
            }
        }

        return $data;
    }

    /**
     * 校验数据结构
     * @param array $data
     * @return array|bool
     */
    public function confirmation($data = array())
    {
        // 判断目录是否存在：防止写入错误
        foreach ($data['dir'] as $item)
        {
            if( is_dir($item) === false )
            {
                $this->error = sprintf('目录【%s】不存在',$item);

                return false;
            }
        }
        // 判断文件是否存在：指的是将要生成的目标文件，防止覆盖已存在文件
        foreach ($data['file'] as $item)
        {
            if( is_file($item) )
            {
                $this->error = sprintf('文件【%s】已存在',$item);

                return false;
            }
        }
        if( empty($data['fetch']) )
        {
            $data['fetch'] = array();
        }
        if( empty($data['templates']) )
        {
            $data['templates'] = array();
        }
        // 自动生成模板校验
        $build = array_merge($data['fetch'],$data['templates']);
        // 无任何文件需要生成就可以退出了
        if( empty($build) )
        {
            $this->error = '无任何文件需要生成';

            return false;
        }
        // 判断生成工具模板文件是否存在
        foreach ($build as $item)
        {
            if( is_file($item) === false )
            {
                $this->error = sprintf('模板【%s】不存在',$item);

                return false;
            }
        }
        // 获取对象视图层目录
        $view = $data['view'];
        // 判断对象视图层目录是否存在
        if( is_dir($view) === false )
        {
            mkdir($view, 0755, true);
        }
        // 无权生成目录的异常处理
        if( is_dir($view) === false )
        {
            $this->error = '生成视图层目录失败';

            return false;
        }
        // 视图层模板直接读取
        foreach ($data['templates'] as $key => &$item)
        {
            $item = file_get_contents($item);

            $search = array(
                sprintf('{module}'),
                sprintf('{target}'),
            );

            $replace = array(
                $data['module'],
                $data['target'],
            );

            $item = str_replace($search, $replace, $item);
        }

        $this->assign('data',$data);


        //读取模板并合并到 templates数组下
        foreach ($data['fetch'] as $key => &$item)
        {
            $data['templates'][$key] = $this->fetch($item);
        }

        return $data;
    }


    public function build($data = array())
    {
        $message = array(sprintf('脚手架【%s/%s】自动生成文件列表',$data['module'],$data['target'] ?? ''));

        foreach ($data['templates'] as $file => $content)
        {
            file_put_contents($file, $content);

            $message[] = $file;
        }

        $destination = sprintf('%s-%s,%s',$data['module'],$data['target'] ?? '',time());

        $message = implode(PHP_EOL, $message);

        Log::record($message.'----'.$destination,'INFO');

        return true;
    }

    public function createModule($module)
    {
        $data['module'] = $module;

        $data['ceng'] = ['controller', 'service', 'servlet'];

        // 模板视图层目录
        $buildView = sprintf('%s%s/%s/%s', APPLICATION_PATH, 'admin', 'view', 'build');

        //构建各层目录及文件的数据结构
        foreach ($data['ceng'] as $key => $val)
        {
            //文件路径
            $data['dir'][$val] = APPLICATION_PATH . $module . '/' . $val;
            //模板文件路径
            $data['templates'][$data['dir'][$val] . '/Base' . ucfirst($val) . '.php'] = $buildView . '/module/' . $val . '/Base' . ucfirst($val) . '.html';
        }

        //添加无模板的层
        $data['dir']['logic'] = APPLICATION_PATH . $module . '/' . 'logic';
        $data['dir']['view']  = APPLICATION_PATH . $module . '/' . 'view';

        $this->assign('module', $module);
        return $data;
    }

    /**
     * 校验模块生成数据结构
     * @param array $data
     * @return array|bool
     */
    public function checkModule($data = [])
    {
        //路径是否存在
        foreach ($data['dir'] as $key => $val)
        {
            if( is_dir($val) )
            {
                $this->error = '目录已存在:' . $val;

                return false;
            }
            mkdir($val, 0755, true);
        }

        //模板是否存在
        foreach ($data['templates'] as $key => $val)
        {
            if( file_exists($val) === false )
            {
                $this->error = '模板文件不存在:' . $val;

                return false;
            }
        }

        return $data;
    }

    /**
     * 提取模板
     * @param array $data
     * @return array
     */
    public function getTemplates($data = [])
    {
        foreach ( $data['templates'] as $key => $val )
        {
            $data['templates'][$key] = $this->fetch($val);
        }

        return $data;
    }
}